import os
import socket
import threading
import time
import keyboard
import queue

from lib.log_udp_server import get_current_ms

udp_client_map = {} #{addr+port: (addr, time)}
udp_map_lock = threading.Lock()
udp_send_queue = queue.Queue(0)

### 监听按键，退出程序
def app_exit(udp):
    udp.close()
    print("Key: CTRL+X")
    os._exit(0)

### 更新udp客户端列表
def update_client_map(addr):
    name = "%s->%d" % (addr[0], addr[1])
    if name not in udp_client_map.keys():
        msg = "APP-->UDP Client Map: add (%s)" % name
        print(msg)
    udp_map_lock.acquire()
    udp_client_map[name] = (addr, get_current_ms())
    udp_map_lock.release()

### 检查udp客户端列表，存在超时就删除
def check_client_map():
    global udp_client_map
    global udp_map_lock
    while True:
        udp_map_lock.acquire()
        cmap = udp_client_map.copy()
        udp_map_lock.release()

        now = get_current_ms()
        for k in cmap.keys():
            if now>cmap[k][1] and now-cmap[k][1]>20000:
                udp_map_lock.acquire()
                del udp_client_map[k]
                udp_map_lock.release()
                print("UDP Client Timeout: remove %s->%d" % (k, len(udp_client_map)))

        if len(udp_client_map)<=0:
            udp_send_queue.queue.clear()
        
        time.sleep(0.1)

### 更新udp客户端列表
def update_client(name, addr):
    global udp_map_lock
    udp_map_lock.acquire()
    udp_client_map[name] = (addr, get_current_ms())
    udp_map_lock.release()

### udp服务器向客户端分发数据
def udp_send_task(udp):
    while True:
        while not udp_send_queue.empty():
            data = udp_send_queue.get()

            if len(data)<=0 or len(udp_client_map)<=0:
                continue

            udp_map_lock.acquire()
            cmap = udp_client_map.copy()
            udp_map_lock.release()
            
            for k,v in cmap.items():
                udp.sendto(data, v[0])

        time.sleep(0.005)

### UDP服务器接收数据任务
def udp_rec_task(udp):
    while True:
        try:
            data, addr = udp.recvfrom(4096)
            if len(data)>0:
                udp_send_queue.put(data)
                update_client_map(addr)

                print("APP-->UDP Server Rec: (%s->%d): %d" % (addr[0], addr[1], len(data)))
        except:
            print("APP->UDP Server Error!!!")

        time.sleep(0.005)

### UDP服务器运行
def udp_server_run(udp):
    td1 = threading.Thread(target=udp_send_task, args=(udp,))
    td1.start()

    td2 = threading.Thread(target=udp_rec_task, args=(udp,))
    td2.start()

def check_run():
    td = threading.Thread(target=check_client_map)
    td.start()

if __name__ == '__main__':
    host = "192.168.43.230"
    port = 14550
    udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_server.bind((host, port))

    keyboard.add_hotkey("ctrl+x", app_exit, args=(udp_server,))

    check_run()    #检查客户端列表，超时则删除
    udp_server_run(udp_server) #UDP服务器发送任务

    while True:
        time.sleep(0.005)

